#ifndef UNARY_EXPRESSION_NODE_H
#define UNARY_EXPRESSION_NODE_H

#include "ExpressionNode.h"

template <class UnaryOperator>
class UnaryExpressionNode: public ExpressionNode {
	public:
		UnaryExpressionNode(ExpressionNode* child):
				_child(child) {}

		~UnaryExpressionNode() {
			delete _child;
		}

		virtual Column pull(const SharedArray<Column>& data) {
			Column in = _child->pull(data);

			UnaryOperator op;
			Type inType = in.type();
			Type outType = op.outType(inType);

			switch (inType) {
				case INT:
					switch (outType) {
						case INT: return compute<int32_t, int32_t>(in);
						case DOUBLE: return compute<int32_t, double>(in);
						case BOOL: return compute<int32_t, bool>(in);
						default: assert(false);
					}

				case DOUBLE:
					switch (outType) {
						case INT: return compute<double, int32_t>(in); 
						case DOUBLE: return compute<double, double>(in); 
						case BOOL: return compute<double, bool>(in); 
						default: assert(false);
					}

				case BOOL:
					switch (outType) {
						case INT: return compute<bool, int32_t>(in); 
						case DOUBLE: return compute<bool, double>(in); 
						case BOOL: return compute<bool, bool>(in); 
						default: assert(false);
					}

				default:
					assert(false);
			}

			return Column();
		}

	private:
		template <typename Tin, typename Tout>
		Column compute(Column in) {
			SharedArray<Tout> out(in.size());
			UnaryOperator op;

			for (int i = 0; i < in.size(); ++i) {
				out[i] = op.compute<Tin, Tout>(in.at<Tin>(i));
			}

			return Column(out);
		}

		ExpressionNode* _child;
};

#endif
